import sample from "@keystonehq/alias-sampling";
import { BlockPermutation, world } from "@minecraft/server";
import { GameComponent } from "@sapi-game/gameComponent";
import { regionHelper } from "@sapi-game/main";
import { EntityTypeIds } from "@sapi-game/utils/vanila-data";
import { BlockedInCombatBlockData } from "../blocks";
import { BlockedLoadState } from "../states/loadState";

export class BlockedRandomMapLoader extends GameComponent<BlockedLoadState> {
    private sampler?: {
        next: (numOfSamples?: number | undefined) => BlockedInCombatBlockData;
    };

    override onAttach(): void {
        this.runner.run(async (r) => {
            try {
                await this.initBlocks();
                this.killAll();
                await r.wait(1);
                await this.fillAir(); //清空场地
                await r.wait(2);
                this.killAll();
                await this.randomBlocks();
                await r.wait(10);
                this.context.groupSet.title("地图生成完成");
                await r.wait(10);
                this.state.next();
            } catch (err) {
                this.context.groupSet.sendMessage("§c地图生成失败，游戏结束");
                this.state.stop(err);
            }
        });
    }

    private async fillAir() {
        const gen = regionHelper.fillGenerator(this.context.map.region, "air");
        const result = this.runner.runJob(gen);
        await result.promise;
    }

    private killAll() {
        const entites = this.context.map.region.getEntitesInRegion({
            excludeTypes: [EntityTypeIds.Player],
        });
        entites.forEach((e) => e.remove());
    }

    private async initBlocks() {
        const blocks = (await import("../blocks")).BlockedInCombatBlocks;

        blocks.forEach((b) => {
            if (b.permutation) return;
            b.permutation = b.buildBlock
                ? b.buildBlock()
                : BlockPermutation.resolve(b.blockId!);
        });

        this.sampler = sample(
            blocks.map((b) => b.prob),
            blocks
        );
    }

    async randomBlocks() {
        const gen = this.BatchBlockGenerator();
        const ans = this.runner.runJob(gen);
        await ans.promise;
    }

    *BatchBlockGenerator(batchSize = 256) {
        if (!this.sampler) return;
        const sampler = this.sampler;
        const region = this.context.map.region;
        const max = region.getMax();
        const min = region.getMin();
        const dim = world.getDimension(region.dimensionId);
        let cnt = 0;

        for (let y = min.y; y <= max.y; y++) {
            for (let x = min.x; x <= max.x; x++) {
                for (let z = min.z; z <= max.z; z++) {
                    let data = sampler.next();
                    const pos = { x, y, z };
                    dim.setBlockPermutation(pos, data.permutation!);
                    if (data.afterSet) {
                        const block = dim.getBlock(pos);
                        if (block) data.afterSet(block);
                    }
                    cnt++;
                    if (cnt >= batchSize) {
                        cnt = 0;
                        yield;
                    }
                }
            }
        }
    }
}
